//
//  LoginViewController.m
//  RACExample
//
//  Created by 山刘 on 2020/5/28.
//  Copyright © 2020 山刘. All rights reserved.
//

#import "LoginViewController.h"
/*================================================宏================================================*/
#define GreenBgColor [UIColor colorWithRed:0.8 green:1.0 blue:0.8 alpha:1]
#define RedBgColor   [UIColor colorWithRed:1.0 green:0.8 blue:0.8 alpha:1]
#define WhiteBgColor [UIColor whiteColor]
#define ConvertInputStateToColor(signal) [InputStateToColorConverter convert:signal]
#define ConvertTextToInputState(signal, minimum, maximum) [TextToInputStateConverter convert:signal m##inimum:minimum m##aximum:maximum]
typedef enum : NSUInteger {
    InputStateEmpty,
    InputStateValid,
    InputStateInvalid
} InputState;

/*================================================V层-InputStateToColorConverter================================================*/
@interface InputStateToColorConverter : NSObject
+ (RACSignal *)convert:(RACSignal *)signal;
@end
@implementation InputStateToColorConverter
+ (RACSignal *)convert:(RACSignal *)signal{
    return [signal map:^id(NSNumber *inputStateNumber) {
        InputState inputState = [inputStateNumber unsignedIntegerValue];
        switch (inputState) {
            case InputStateValid:
                return GreenBgColor;
            case InputStateInvalid:
                return RedBgColor;
            default:
                return WhiteBgColor;
        }
    }];
}
@end
/*================================================V层-TextToInputStateConverter================================================*/
@interface TextToInputStateConverter : NSObject
+ (RACSignal *)convert:(RACSignal *)signal minimum:(NSInteger)minimum maximum:(NSInteger)maximum;
+ (InputState)inputStateForText:(NSString *)text minimum:(NSInteger)minimum maximum:(NSInteger)maximum;
@end
@implementation TextToInputStateConverter
+ (RACSignal *)convert:(RACSignal *)signal minimum:(NSInteger)minimum maximum:(NSInteger)maximum{
    NSAssert(minimum > 0, @"TextToInputStateConverter: minimum must be greater than zero");
    NSAssert(maximum >= minimum, @"TextToInputStateConverter: maximum must be greater than or equal to minimum");
    return [signal map:^id(NSString *text) {
        return @([TextToInputStateConverter inputStateForText:text minimum:minimum maximum:maximum]);
    }];
}
+ (InputState)inputStateForText:(NSString *)text minimum:(NSInteger)minimum maximum:(NSInteger)maximum{
    if ([text length] >= minimum && [text length] <= maximum) {
        return InputStateValid;
    } else {
        if ([text length] == 0) {
            return InputStateEmpty;
        } else {
            return InputStateInvalid;
        }
    }
}
@end
#pragma mark - ====================VM层====================
@interface LoginViewModel : NSObject
@property (copy, nonatomic) NSString *usename;
@property (copy, nonatomic) NSString *password;

@property (nonatomic, assign, readonly) InputState usernameInputState;
@property (nonatomic, assign, readonly) InputState passwordInputState;
@property (nonatomic, assign, readonly) BOOL loginEnabled;
@end

@interface LoginViewModel()
@property (nonatomic, assign, readwrite) InputState usernameInputState;
@property (nonatomic, assign, readwrite) InputState passwordInputState;
@property (nonatomic, assign, readwrite) BOOL loginEnabled;
@end

@implementation LoginViewModel
#pragma mark - init
-(instancetype)init{
    if (self = [super init]) {
        [self racInit];
    }
    return self;
}
#pragma mark - business
- (void)racInit {
    RAC(self,usernameInputState) = ConvertTextToInputState(RACObserve(self,usename), 2, 4);
    RAC(self,passwordInputState) = ConvertTextToInputState(RACObserve(self,password), 5, 10);
    
    RAC(self,loginEnabled) = [RACSignal combineLatest:@[RACObserve(self,usernameInputState),RACObserve(self,passwordInputState)] reduce:^id(NSNumber *usernameInputStateValue,NSNumber *passwordInputStateValue){
        if ([usernameInputStateValue unsignedIntegerValue] == InputStateValid &&
            [passwordInputStateValue unsignedIntegerValue] == InputStateValid) {
            return @(YES);
        }
        return @(NO);
    }];
}
#pragma mark - getter
@end

#pragma mark - ====================V层====================
@interface LoginViewController ()
@property (weak, nonatomic) IBOutlet UITextField *usenameTextField;
@property (weak, nonatomic) IBOutlet UITextField *passwordTextFeidl;
@property (weak, nonatomic) IBOutlet UIButton *loginButton;
@property(nonatomic, strong) LoginViewModel *viewModel;
@end

@implementation LoginViewController
- (void)viewDidLoad {
    [super viewDidLoad];
    [self segInitViews];
    [self bindViewModel];
}

#pragma mark - init Views
-(void)segInitViews{
}

#pragma mark - RAC Data Binding
- (void)bindViewModel {
    // bind input signals
    RAC(self.viewModel,usename) = self.usenameTextField.rac_textSignal;
    RAC(self.viewModel,password) = self.passwordTextFeidl.rac_textSignal;
    // bind output signals
    RAC(self.usenameTextField,backgroundColor) = ConvertInputStateToColor(RACObserve(self.viewModel, usernameInputState));
    RAC(self.passwordTextFeidl,backgroundColor) = ConvertInputStateToColor(RACObserve(self.viewModel, passwordInputState));
    RAC(self.loginButton, enabled) = RACObserve(self.viewModel, loginEnabled);
    [[self.loginButton rac_signalForControlEvents:UIControlEventTouchUpInside] subscribeNext:^(__kindof UIControl * _Nullable x) {
        NSLog(@"Login....");
    }];
}

#pragma mark - getter
-(LoginViewModel *)viewModel{
    if (!_viewModel) {
        _viewModel = [[LoginViewModel alloc]init];
    }
    return _viewModel;
}
@end
